#include "FunctionBuilder.h"
#include "ScriptCompiler/ScriptFileContext.h"

#include "ScriptCompiler/AST/FunctionNode.h"
#include "ScriptCompiler/AST/DecoratorNode.h"

#include "ScriptCompiler/ASTBuilder/FunctionParameterBuilder.h"
#include "ScriptCompiler/ASTBuilder/SentenceBlockBuilder.h"
#include "ScriptCompiler/ASTBuilder/TypeBuilder.h"
#include "ScriptCompiler/ASTBuilder/ExpressionBuilder.h"
#include "ScriptCompiler/ASTBuilder/FunctionContentBuilder.h"


CFunctionBuilder::CFunctionBuilder(std::shared_ptr<CScriptFileContext> InContext)
{
    Context = InContext;
    Result = std::make_shared<CFunctionNode>(Context);
}

bool CFunctionBuilder::ReadCurentToken()
{

    {
        auto NameToken = Context->GetCurrentToken();

        if (NameToken->Type != EScriptTokenType::Identifier)
        {
            Context->RaiseError(10052,NameToken,U"Expected function name");
            return false;
        }
        
        Result->Name = NameToken;
        Context->CurrentTokenIndex++;
    } 

    {
        auto LeftParenthesesToken = Context->GetCurrentToken();
        if (LeftParenthesesToken->Type != EScriptTokenType::LeftParentheses)
        {
            Context->RaiseError(10053,LeftParenthesesToken,U"Expected left parenthesis");
            return false;
        }

        Context->CurrentTokenIndex++;
    }

    {

        auto RightParenthesesToken = Context->GetCurrentToken();
        while(RightParenthesesToken->Type != EScriptTokenType::RightParentheses)
        {
            auto ParameterBuilder = std::make_shared<CFunctionParameterBuilder>(Context);
            if (!ParameterBuilder->ReadCurentToken())
            {
                return false;
            }

            Result->Parameters.Add(ParameterBuilder->Result);

            auto CommaToken = Context->GetCurrentToken();
            if (CommaToken->Type == EScriptTokenType::Comma)
            {
                Context->CurrentTokenIndex++; 
            }
            else if (CommaToken->Type == EScriptTokenType::RightParentheses)
            {
                break;
            }
            else
            {
                Context->RaiseError(10054,CommaToken,U"Expected comma or right parenthesis after parameter");
                return false;
            }

            RightParenthesesToken = Context->GetCurrentToken();
        }

        //in case empty parameter name
        auto CommaToken = Context->GetFormerToken();
        if(CommaToken->Type == EScriptTokenType::Comma)
        {
            Context->RaiseError(10055,CommaToken,U"Expected parameter after comma");
            return false;
        }

        Context->CurrentTokenIndex++; //skip right parenthesis
    }

    //check if have content
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type == EScriptTokenType::Semicolon)
        {
            //this is a declaration, no content
            Context->CurrentTokenIndex++; //skip semicolon
            return true;
        }
    }

    {
        auto LambdaToken = Context->GetCurrentToken();

        switch (LambdaToken->Type)
        {
            case EScriptTokenType::LeftBrace:
            case EScriptTokenType::LambdaOperator:
            {
                auto ContentBuilder = std::make_shared<CFunctionContentBuilder>(Context);
                if (!ContentBuilder->ReadCurentToken())
                {
                    return false;
                }
                Result->Content = ContentBuilder->Result;
                return true;
            }

            default:
            {
                Context->RaiseError(10056,LambdaToken,U"Expected ';' or '{' or '=>' after function parameters");
                return false;
            }
        }
    }



}
